package main

import (
	"bufio"
	"bytes"
	"fmt"
	log "github.com/Sirupsen/logrus"
	"github.com/jessevdk/go-flags"
	"go-plantuml/codeanalysis"
	"go/build"
	"io"
	"os"
	"os/exec"
	"path"
	"sort"
	"strings"
)

func main() {

	log.SetLevel(log.InfoLevel)

	var opts struct {
		CodeDir       string `long:"codedir" description:"要扫描的代码目录" required:"false"`
		GopathDir     string `long:"gopath" description:"GOPATH目录" required:"false"`
		PackageRep    string `long:"pr" description:"需要替换的包路径字符串，:分割k-v, ,分隔多个，【没有用了】" required:"false"`
		OutputFile    string `long:"outputfile" description:"解析结果保存到该文件中" required:"false"`
		IgnoreDirs    string `long:"ignoredir" description:"需要排除的目录,不需要扫描和解析，英文逗号分隔,如果以-开头，表示后面逗号分隔的，是只要路径中包含这些名称都跳过"`
		IgnoreDirName string `long:"ignoredirName" description:"英文逗号分隔,只要路径中包含这些名称都跳过"`
		Project       string `long:"pg" description:"工程文件夹名称" required:"false"`
		SvgJar        string `long:"svgjar" description:"解析jar包路径" required:"false"`
		ParseCmd      string `long:"pcmd" description:"解析的文件名称" required:"false"`
	}

	_, err := flags.ParseArgs(&opts, os.Args)
	if opts.ParseCmd != "" {
		fs, err := os.Open(opts.ParseCmd)
		if err != nil {
			log.Fatal(err)
			return
		}
		ExeFile(fs)
		return
	} else {
		if opts.Project == "" || opts.SvgJar == "" {
			fmt.Println("工程文件夹名称和svgjar路径必填")
			return
		}
	}
	var gopath = opts.GopathDir
	if opts.GopathDir == "" {
		gopath = strings.Split(os.Getenv("GOPATH"), ";")[0]
		if gopath == "" {
			gopath = strings.Split(build.Default.GOPATH, ";")[0]
		}
	}

	if opts.CodeDir == "" {
		opts.CodeDir = gopath + "\\src\\" + opts.Project
	}
	if opts.OutputFile == "" { //使用固定名称
		opts.OutputFile = opts.CodeDir + "\\plantuml.puml"
	} else if opts.OutputFile == "-" { //使用工程名称，会替换掉里面的斜杠
		na := strings.ReplaceAll(opts.Project, "/", "_")
		na = strings.ReplaceAll(na, "\\\\", "_")
		na = strings.ReplaceAll(na, "\\", "_")
		opts.OutputFile = opts.CodeDir + "\\" + na + ".puml"
	} else {
		// 使用输入的文件路径 E://GoGo/ff.puml
	}

	if len(opts.IgnoreDirs) == 0 {
		opts.IgnoreDirs = strings.Join([]string{opts.CodeDir + "\\proto", opts.CodeDir + "\\vendor"}, ",")
	} else {
		opts.IgnoreDirs = strings.Join([]string{opts.IgnoreDirs, opts.CodeDir + "\\proto", opts.CodeDir + "\\vendor"}, ",")
	}
	fmt.Println(opts)
	if err != nil {
		os.Exit(1)
	}
	//--codedir="E:/GoWork/src/gamechat" --gopath="E:/GoWork" --outputfile="E:/GoWork/src/go-package-plantuml/pp.puml" --ignoredir="E:/GoWork/src/gamechat/vendor"
	//

	if !strings.HasPrefix(opts.CodeDir, opts.GopathDir) {
		panic(fmt.Sprintf("代码目录%s,必须是GOPATH目录%s的子目录", opts.CodeDir, opts.GopathDir))
		os.Exit(1)
	}
	ignor := strings.Split(opts.IgnoreDirs, ",")
	for _, dir := range ignor {
		if !strings.HasPrefix(dir, opts.CodeDir) {
			panic(fmt.Sprintf("需要排除的目录%s,必须是代码目录%s的子目录", dir, opts.CodeDir))
			os.Exit(1)
		}
	}
	sb := strings.Builder{}
	for i := range opts.Project {
		if opts.Project[i] == '-' {
			sb.WriteByte('_')
		} else {
			sb.WriteByte(opts.Project[i])
		}
	}
	opts.Project = sb.String()
	pr := make(map[string]string)
	if opts.PackageRep != "" {
		p := strings.Split(opts.PackageRep, ",")
		for _, s := range p {
			sv := strings.Split(s, ":")
			if len(sv) != 2 {
				continue
			}
			pr[sv[0]] = sv[1]
		}
	}
	aa := codeanalysis.Arr{}
	for k, _ := range pr {
		aa = append(aa, k)
	}
	sort.Sort(aa)

	ignoreDirNames := strings.Split(opts.IgnoreDirName, ",")

	config := codeanalysis.Config{
		CodeDir:        opts.CodeDir,
		GopathDir:      opts.GopathDir,
		ProjectName:    opts.Project,
		PackageRep:     pr,
		PackageRepSort: aa,
		VendorDir:      path.Join(opts.CodeDir, "vendor"),
		IgnoreDirs:     ignor,
		IgnoreDirName:  ignoreDirNames,
		OutputFile:     opts.OutputFile,
		SvgJar:         opts.SvgJar,
	}

	result := codeanalysis.AnalysisCode(config)

	result.OutputToFile(opts.OutputFile)
	svg(config)
}

func svg(config codeanalysis.Config) {
	javaRoot := os.Getenv("JAVA_HOME")
	if javaRoot == "" {
		return
	}
	cmd := exec.Command("cmd")
	// cmd := exec.Command("powershell")
	in := bytes.NewBuffer(nil)
	cmd.Stdin = in //绑定输入
	var out bytes.Buffer
	cmd.Stdout = &out //绑定输出
	go func() {
		// start stop restart
		in.WriteString(fmt.Sprintf("java -jar %v %v -tsvg  -charset UTF-8 \n", config.SvgJar, config.OutputFile)) //写入你的命令，可以有多行，"\n"表示回车
		//go func() {
		//	// start stop restart
		//	in.WriteString(fmt.Sprintf("java -jar %v %v -tpng -charset UTF-8 \n", config.SvgJar, config.OutputFile)) //写入你的命令，可以有多行，"\n"表示回车
		//}()
	}()
	err := cmd.Start()
	if err != nil {
		log.Fatal(err)
	}
	log.Println(cmd.Args)
	err = cmd.Wait()
	if err != nil {
		log.Printf("Command finished with error: %v", err)
	}
	rt := out.String() //mahonia.NewDecoder("gbk").ConvertString(out.String()) //
	fmt.Println(rt)
}

func ExeFile(fs io.Reader) {
	buf := bufio.NewReader(fs)
	for {
		s, _, err := buf.ReadLine()
		if err == io.EOF {
			break
		} else if err != nil {
			fmt.Println(err)
			break
		}
		cm := string(s)
		if len(strings.TrimSpace(cm)) == 0 {
			continue
		}
		cmd := exec.Command("cmd")
		// cmd := exec.Command("powershell")
		in := bytes.NewBuffer(nil)
		cmd.Stdin = in //绑定输入
		var out bytes.Buffer
		cmd.Stdout = &out //绑定输出
		go func() {
			in.WriteString(fmt.Sprintf("%s \n", cm))
		}()
		err = cmd.Start()
		if err != nil {
			log.Fatal(err)
		}
		log.Println(cmd.Args)
		err = cmd.Wait()
		if err != nil {
			log.Printf("Command finished with error: %v", err)
		}
		rt := out.String() //mahonia.NewDecoder("gbk").ConvertString(out.String()) //
		fmt.Println(rt)
	}
	fmt.Println("over")
}
